home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
demos
/
GL
/
newton
/
physics.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
10KB
|
446 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* physics calculations of the model motion
* Yossi Friedman, July 1988
*/
#include <stdio.h>
#include <gl.h>
#include <math.h>
#include "config.h"
#include "newton.h"
#include "slider.h"
/* free physical parameters */
float gravity; /* current gravity */
float wall_k; /* spring constant of the walls */
float fric; /* friction of the wall */
float air_damp; /* air friction */
float disp_step; /* display time increment */
/* dependent physical parameters */
static float dt; /* computation time increment */
static float t; /* current time, modulo dt */
float grav_vec_V[3]; /* real gravity vector (in viewing system) */
float grav_vec[3]; /* gravity vector in modeling coord system */
struct slider *k_slider; /* ptr. to K slider */
void new_gravity(float), new_k(float),
new_wall_k(float), new_fric(float),
new_air_damp(float), new_disp_step(float);
initialize_physics()
{
/* gravity vector should point down in the viewing coordinate system */
grav_vec_V[X] = grav_vec_V[Z] = 0.;
/* set the sliders properly */
initialize_slider_parameters();
t = 0.;
stop_gravity();
}
initialize_slider_parameters()
{
struct slider *sp;
sp = sliders;
sp->title = "Gravity";
sp->lo = 0.;
sp->hi = 0.4;
sp->dflt = 0.1;
sp->fun = new_gravity;
sp++;
sp->title = "Spring Constant";
sp->lo = 0.1;
sp->hi = 50.;
/* sp->dflt = max_k; */
sp->dflt = 0.; /* dummy */
sp->fun = new_k;
k_slider = sp;
sp++;
sp->title = "Wall Stiffness";
sp->lo = 0.01;
#if ECLIPSE || CLOVER1 /* the slow machines */
sp->hi = 0.8;
sp->dflt = 0.3;
#else /* ECLIPSE || CLOVER1 */
sp->hi = 1.5;
sp->dflt = 0.8;
#endif /* ECLIPSE || CLOVER1 */
sp->fun = new_wall_k;
sp++;
sp->title = "Wall Friction";
sp->lo = 1. - 1.;
sp->hi = 1. - 0.5;
sp->dflt = 1. - 0.9;
sp->fun = new_fric;
sp++;
sp->title = "Air Dampening";
sp->lo = 1. - 1.;
sp->hi = 1. - 0.99;
sp->dflt = 1. - 0.9995;
sp->fun = new_air_damp;
sp++;
sp->title = "Display Step";
sp->lo = 1.;
sp->hi = 7.;
#if ECLIPSE || CLOVER1 /* the slow machines */
sp->dflt = 6.5;
#else /* ECLIPSE || CLOVER1 */
sp->dflt = 3.0;
#endif /* ECLIPSE || CLOVER1 */
sp->fun = new_disp_step;
sp++;
end_sliders = sp;
}
void
new_gravity(float val)
{
gravity = val;
if (grav_vec_V[Y] != 0.) {
grav_vec_V[Y] = gravity;
/* get the gravity vector to point down properly */
apply(grav_vec, grav_vec_V, M_inv);
}
}
void
new_k(float val)
{
Spring *spring;
float k;
if (val == 0.) /* dummy */
return;
for (spring = model_springs; spring < end_model_springs TOTAL; spring++)
spring->k *= val/max_k;
max_k = val;
/* calculate dt */
k = (max_k > wall_k)? max_k: wall_k;
dt = sqrt(2./k) * 0.5; /* fifty percent thumb rule */
}
void
new_wall_k(float val)
{
wall_k = val;
}
void
new_fric(float val)
{
fric = 1. - val;
}
void
new_air_damp(float val)
{
air_damp = 1. - val;
}
void
new_disp_step(float val)
{
disp_step = val;
}
stop_gravity()
{
grav_vec[X] =
grav_vec[Y] =
grav_vec[Z] =
grav_vec_V[X] =
grav_vec_V[Y] =
grav_vec_V[Z] = 0.0;
}
start_gravity()
{
grav_vec_V[Y] = gravity;
/* get the gravity vector to point down properly */
apply(grav_vec, grav_vec_V, M_inv);
}
void
set_default_k(float k)
{
set_slider_default(k_slider->sid, k);
set_k(k);
}
void
set_k(float k)
{
set_slider(k_slider->sid, k);
}
/*
* rotate the physics (gravity and model atoms vectors) in the ROOM
* coordinate system angle alpha around a VIEWING axis
*/
rotate_physics(Angle alpha, char axis)
{
/* first get the gravity vector to point down properly */
apply(grav_vec, grav_vec_V, M_inv);
/*
* the formula is:
* v R = v M rot M_inv,
* where rot is the rotation matrix (in the viewing system) around the
* viewing axis.
*/
pushmatrix();
loadmatrix(M_inv);
rotate(alpha, axis);
multmatrix(M);
getmatrix(R);
popmatrix();
SLAVE_FUNC(DO_ROTATE_PHYSICS);
do_rotate_physics(model_atoms, end_model_atoms MASTER);
WAIT_FOR_SLAVE();
}
do_rotate_physics(Atom *start, Atom *finish)
{
Atom *ap;
float ov[3], *v;
for (ap = start; ap < finish; ap++) {
v = ap->pos;
ov[X] = v[X]; ov[Y] = v[Y]; ov[Z] = v[Z];
apply(v, ov, R);
v = ap->vel;
ov[X] = v[X]; ov[Y] = v[Y]; ov[Z] = v[Z];
apply(v, ov, R);
}
}
iterate()
{
if(dt <= 0.0)
return;
for (; t < disp_step; t += dt) {
SLAVE_FUNC(DO_CLEAR);
do_clear(model_atoms, end_model_atoms MASTER);
WAIT_FOR_SLAVE();
wall[0].penetrated = wall[1].penetrated = wall[2].penetrated =
wall[3].penetrated = wall[4].penetrated = wall[5].penetrated = 0;
wall[0].depth = wall[1].depth = wall[2].depth =
wall[3].depth = wall[4].depth = wall[5].depth = 0;
SLAVE_FUNC(DO_ACCEL);
do_accel(model_springs, end_model_springs MASTER MASTER_PARAM);
WAIT_FOR_SLAVE();
SLAVE_FUNC(DO_BOUNDS);
do_bounds(model_atoms, end_model_atoms MASTER);
WAIT_FOR_SLAVE();
SLAVE_FUNC(DO_VEL_DAMP_POS);
do_vel_damp_pos(model_atoms, end_model_atoms MASTER);
WAIT_FOR_SLAVE();
}
t -= disp_step;
}
do_clear(Atom *start, Atom *finish)
{
Atom *ap;
for(ap = start; ap < finish; ap++) {
ap->acc MASTER [X] = -grav_vec[X] * dt;
ap->acc MASTER [Y] = -grav_vec[Y] * dt;
ap->acc MASTER [Z] = -grav_vec[Z] * dt;
#ifdef MP
{
int i;
for (i = 1; i < nproc; i++) {
ap->acc [i] [X] =
ap->acc [i] [Y] =
ap->acc [i] [Z] = 0.;
}
}
#endif /* MP */
}
}
do_accel(Spring *start, Spring *finish, CPU_PARAM_TYPE)
{
Spring *spring;
float r[3], lri, a[3], F;
for (spring = start; spring < finish; spring++) {
vec_op(r, spring->from->pos, -, spring->to->pos);
lri = 1. / sqrt(r[X]*r[X] + r[Y]*r[Y] + r[Z]*r[Z]);
r[X] *= lri;
r[Y] *= lri;
r[Z] *= lri;
F = spring->k * (1. - spring->r0*lri) * 0.5;
/* the division by 2 above is because half the force is applied
on each endpoint */
a[X] = r[X] * F;
a[Y] = r[Y] * F;
a[Z] = r[Z] * F;
vec_op(spring->from->acc CPU, spring->from->acc CPU, -, a);
vec_op(spring->to->acc CPU, spring->to->acc CPU, +, a);
}
}
do_bounds(Atom *start, Atom *finish)
{
Atom *ap;
/*
* do_wall is a tricky code that checks weather an atom penetrated a wall.
* if it did, do_dent applies a force on the atom with a direction back into
* the room and a magnitude proportional to the penetration depth (i.e., the
* wall springs are linear). It also calls do_dent to record the amount of
* dent in the wall, for when the wall is drawn.
*
* The room is the cube { x \in [-HEIGHT,+HEIGHT]^3 }.
*
* If you absolutely have to go throught this code, re-write it manually
* for a specific wall, and notice the symmetry conditions implied for all
* walls. Note that if the wall is on AXIS, the other two axises can
* be obtained by (AXIS+1)%3 and (AXIS+2)%3.
*/
#define do_wall(WALL, AXIS, sgn) \
/* int WALL; int AXIS; sign sgn; */ \
do { \
float depth = 0. sgn (ap->pos[AXIS] - (0. sgn HEIGHT)); \
\
if (depth > 0.) { \
\
/* apply forces from wall */ \
ap->acc MASTER [AXIS] -= wall_k * (0. sgn depth); \
ap->vel[(AXIS+1)%3] *= fric; \
ap->vel[(AXIS+2)%3] *= fric; \
\
/* record deepest penetration position */ \
if ((depth - wall[WALL].depth) > \
(TOLERANCE * TOLERANCE - 1.) * \
HEIGHT \
) { \
wall[WALL].penetrated = 1; \
wall[WALL].atom = ap; \
\
wall[WALL].depth = depth; \
} \
} \
} while (0)
for (ap = start; ap < finish; ap++) {
do_wall(WALL_BOTTOM, Y, -);
do_wall(WALL_TOP, Y, +);
do_wall(WALL_LEFT, X, -);
do_wall(WALL_RIGHT, X, +);
do_wall(WALL_BACK, Z, -);
do_wall(WALL_FRONT, Z, +);
}
#undef do_wall
}
do_vel_damp_pos(Atom *start, Atom *finish)
{
Atom *ap;
for (ap = start; ap < finish; ap++) {
#ifdef MP
{
int i;
for (i = 1; i < nproc; i++)
vec_op(ap->acc MASTER, ap->acc MASTER, +, ap->acc[i]);
}
#endif /* MP */
/* calculate the velocity */
vec_op(ap->vel, ap->vel, +, dt * ap->acc MASTER);
/* calculate air dampening */
ap->vel[X] *= air_damp;
ap->vel[Y] *= air_damp;
ap->vel[Z] *= air_damp;
/* calculate position */
vec_op(ap->pos, ap->pos, +, dt * ap->vel);
}
}